package board;

import gamerule.ShipPlacementException;
import ship.Ship;

/**
 * @author tymoshya
 * @since 8/5/11
 */
public class Shipyard {

    private Board board;

    public Shipyard(Board board) {
        this.board = board;
    }


    public void place(Ship ship)
            throws ShipPlacementException {
        if (isPlaceable(ship)) {
            markShipCoordinatesOccupied(ship);
            markNeighbourCoordinatesOccupied(ship);
        } else {
            throw new ShipPlacementException("Can't place ship " + ship + " here!");
        }

    }

    private void markShipCoordinatesOccupied(Ship ship) {
        int[][] field = board.getBattleField();
        for (Coordinate c : ship.getCoordinates())
            field[c.getVertical()][c.getHorizontal()] = Coordinate.Status.DECK;
    }

    private void markNeighbourCoordinatesOccupied(Ship ship) {
        int[][] field = board.getBattleField();
        int firstV = ship.getFirstCoordinate().getVertical();
        int firstH = ship.getFirstCoordinate().getHorizontal();
        int lastV = ship.getLastCoordinate().getVertical();
        int lastH = ship.getLastCoordinate().getHorizontal();
        int b, e;

        if (ship.getDirection() == Direction.HORIZONTAL) {
            b = firstH - 1;
            e = lastH + 1;
            for (int i = b; i <= e; i++) {
                //down
                field[firstV - 1][i] = markField();
                //up
                field[firstV + 1][i] = markField();
            }
            //left
            field[firstV][firstH - 1] = markField();
            //right
            field[lastV][lastH + 1] = markField();
        } else { // vertical
            b = firstV - 1;
            e = lastV + 1;
            //down
            field[lastV + 1][lastH] = markField();
            //up
            field[firstV - 1][firstH] = markField();
            for (int i = b; i <= e; i++) {
                //left
                field[i][firstH - 1] = markField();
                //right
                field[i][firstH + 1] = markField();
            }
        }
    }

    private int markField() {
        return Coordinate.Status.NEXT_TO_SHIP;
    }

    private boolean isPlaceable(Ship ship) {
        return isWithinBoard(ship) && isAllCoordinatesFree(ship);
    }

    private boolean isWithinBoard(Ship ship) {
        int width = board.getWidth();
        int height = board.getHeight();
        int h1 = ship.getFirstCoordinate().getHorizontal();
        int v1 = ship.getFirstCoordinate().getVertical();
        int h2 = ship.getLastCoordinate().getHorizontal();
        int v2 = ship.getLastCoordinate().getVertical();

        return ((h1 >= 0) && (h1 < width)) && ((v1 >= 0) && (v1 < height))
                && ((h2 >= 0) && (h2 < width) && ((v2 >= 0) && (v2 < height)));
    }

    private boolean isAllCoordinatesFree(Ship ship) {
        int[][] battlefield = board.getBattleField();

        for (Coordinate c : ship.getCoordinates())
            if (!(battlefield[c.getVertical()][c.getHorizontal()] == Coordinate.Status.FREE))
                return false;

        return true;
    }
}
